﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

// -----------------------------------------------------------------------
// <copyright file="$safeitemrootname$.cs" company="$registeredorganization$">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------
namespace ObjectLibrary
{
    public class MyTerrainModel : MyModel
    {
        private VertexPositionColor[] _vertices;
        private int nRow;
        private int nCol;
        private int nTriangle;
        private int nV;
        private float[,] H;
        private float parameter = 4.5f;
        private float parameter2 = 7;
        private Effect _effect;

        private Texture2D _water, _grass, _ground, _snow;

        private Vector2 _size;

        public Vector2 Size
        {
            get { return _size; }
            set { _size = value; }
        }

        public MyTerrainModel(ContentManager content, string strHeightMapTexture, float scale, Vector3 pos, float rotationY)
        {
            _scale = scale;
            _rotationY = rotationY;
            _position = pos;

            _transformMatrix = Matrix.CreateRotationY(_rotationY) * Matrix.CreateScale(new Vector3(_scale, _scale / parameter2, _scale)) * Matrix.CreateTranslation(_position);
            _effect = content.Load<Effect>(@"Resources/Effects/Terrain");

            Texture2D heightMapTexture = content.Load<Texture2D>(strHeightMapTexture);
            Size = scale * new Vector2(heightMapTexture.Width, heightMapTexture.Height);
            string mapName = strHeightMapTexture.Substring(14, 5);
            _water = content.Load<Texture2D>(@"Resources/Map/" + mapName + @"/MapTextures/water");
            _grass = content.Load<Texture2D>(@"Resources/Map/" + mapName + @"/MapTextures/grass");
            _ground = content.Load<Texture2D>(@"Resources/Map/" + mapName + @"/MapTextures/ground");
            _snow = content.Load<Texture2D>(@"Resources/Map/" + mapName + @"/MapTextures/snow");

            nRow = heightMapTexture.Height - 1;
            nCol = heightMapTexture.Width - 1;
            nTriangle = 2 * nRow * nCol;
            nV = 3 * nTriangle;

            Color[] heightMapColor = new Color[heightMapTexture.Width * heightMapTexture.Height];
            heightMapTexture.GetData(heightMapColor);

            H = new float[heightMapTexture.Height, heightMapTexture.Width];
            for (int i = 0; i < heightMapTexture.Height; i++)
                for (int j = 0; j < heightMapTexture.Width; j++)
                    H[i, j] = heightMapColor[i * heightMapTexture.Width + j].R / parameter;

            _vertices = new VertexPositionColor[nV];

            int iCell = 0;
            for (int x = 0; x < nCol; x++)
                for (int z = 0; z < nRow; z++)
                {
                    //  ----> x
                    //  |
                    //  |
                    //  z

                    //  A -- B
                    //  |    |
                    //  D -- C

                    _vertices[iCell * 6 + 0] = new VertexPositionColor(new Vector3(x, H[z, x], z), Color.White); // A
                    _vertices[iCell * 6 + 1] = new VertexPositionColor(new Vector3(x + 1, H[z, x + 1], z), Color.White); // B
                    _vertices[iCell * 6 + 2] = new VertexPositionColor(new Vector3(x + 1, H[z + 1, x + 1], z + 1), Color.White); // C
                    _vertices[iCell * 6 + 3] = new VertexPositionColor(new Vector3(x, H[z, x], z), Color.White); // A
                    _vertices[iCell * 6 + 4] = new VertexPositionColor(new Vector3(x + 1, H[z + 1, x + 1], z + 1), Color.White); // C
                    _vertices[iCell * 6 + 5] = new VertexPositionColor(new Vector3(x, H[z + 1, x], z + 1), Color.White);    // D
                    iCell++;
                }
        }

        public override void Draw(GameTime gameTime, GraphicsDevice graphicsDevice, Effect effect, MyCamera camera)
        {
            _effect.CurrentTechnique = _effect.Techniques["Technique1"];
            _effect.Parameters["World"].SetValue(TransformMatrix);
            _effect.Parameters["View"].SetValue(camera.View);
            _effect.Parameters["Projection"].SetValue(camera.Projection);
            _effect.Parameters["WaterTexture"].SetValue(_water);
            _effect.Parameters["GrassTexture"].SetValue(_grass);
            _effect.Parameters["GroundTexture"].SetValue(_ground);
            _effect.Parameters["SnowTexture"].SetValue(_snow);
            _effect.Parameters["nWidth"].SetValue(nCol + 1);
            _effect.Parameters["nHeight"].SetValue(nRow + 1);

            foreach (EffectPass pass in _effect.CurrentTechnique.Passes)
            {
                pass.Apply();
                graphicsDevice.DrawUserPrimitives<VertexPositionColor>(
                    PrimitiveType.TriangleList, _vertices, 0, nTriangle,
                    VertexPositionColor.VertexDeclaration);
            }
        }

        public float getHeight(Vector3 Pos)
        {
            Vector3 OriginalPos = (Pos - Position) / Scale;// / Scale - Position;
            OriginalPos.Y = 0;
            if (OriginalPos.X > 0 && OriginalPos.X < nCol
                && OriginalPos.Z > 0 && OriginalPos.Z < nRow)
            {
                int index = ((int)OriginalPos.X * nRow + (int)OriginalPos.Z) * 6;

                Vector3 A = _vertices[index].Position;//a
                Vector3 B = _vertices[index + 1].Position;//b
                Vector3 C = _vertices[index + 2].Position;//c
                Vector3 D = _vertices[index + 5].Position;//d

                Vector3 targetPos;
                float dz = OriginalPos.Z - A.Z;
                float dx = OriginalPos.X - A.X;


                if (dz > dx)
                {
                    Vector3 M1 = D + (A - D) * (1-dz);
                    Vector3 M2 = C + (A - C) * (1-dz);
                    targetPos = M1 + (M2 - M1) * (dx/(M2.X - M1.X));
                }
                else
                {
                    
                    Vector3 M1 = B + (C - B) * (dz);
                    Vector3 M2 = A + (C - A) * (dz);
                    targetPos = M1 + (M2 - M1) * ((1 - dx) / (M1.X - M2.X));
                }

                /*
                float dxA = Math.Abs(OriginalPos.X - A.X);
                float dxC = Math.Abs(OriginalPos.X - C.X);
                float dxAC = Math.Abs(A.X - C.X);

                float HeightA = H[(int)OriginalPos.Z, (int)OriginalPos.X];
                float HeightC = H[(int)OriginalPos.Z + 1, (int)OriginalPos.X + 1];
                return (dxA / (dxA + dxC) * HeightA + dxC / (dxA + dxC) * HeightC) * Scale / parameter2;*/
                return targetPos.Y * (_scale / parameter2);
            }
            return 0;
        }
    }
}
